﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;

using Microsoft.TeamFoundation.Client;

using TFSCommon.Settings;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.Server;

namespace TFSCommon
{
    class TFSProvider
    {
        MySettingsManager Settings { get; set; }

        TfsTeamProjectCollection server_ = null;

        public TFSProvider(MySettingsManager settings)
        {
            Settings = settings;
            Settings.ParameterAfterChange += new Common.ParameterChangeHandler(Settings_ParameterAfterChange);
        }

        void Settings_ParameterAfterChange(object sender, Common.ParameterChangeArgs args)
        {
            if (null != server_)
            {
                Connect();
            }
        }

        public void Connect()
        {
            Disconnect();

            server_ = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(Settings.CollectionUri));
            server_.EnsureAuthenticated();
        }

        public void Disconnect()
        {
            if (null != server_)
            {
                server_.Dispose();
                server_ = null;
            }
        }

        public WorkItemStore GetWorkItemStore()
        {
            return server_.GetService<WorkItemStore>();
        }

        public bool ProjectExists(string project_name)
        {
            return null != GetProject(project_name);
        }

        public Project GetProject()
        {
            return GetProject(Settings.Project);
        }

        public Project GetProject(string project_name)
        {
            WorkItemStore store = GetWorkItemStore();

            foreach (Project p in store.Projects)
            {
                if (p.Name == project_name)
                    return p;
            }

            return null;
        }

        public List<string> GetIterationList(bool add_empty_item)
        {
            return GetIterationList(Settings.Project, add_empty_item);
        }

        public List<string> GetIterationList(string project_name, bool add_empty_item)
        {
            List<string> result = new List<string>();

            if (add_empty_item)
                result.Add(string.Empty);

            result.Add(project_name);
            result.AddRange(RecurseIterationNode(project_name, GetProject(project_name).IterationRootNodes));

            return result;
        }

        public List<string> GetFieldValues(string item_type, string field, bool add_empty_item)
        {
            return GetFieldValues(Settings.Project, item_type, field, add_empty_item);
        }

        public List<string> GetFieldValues(string project_name, string item_type, string field, bool add_empty_item)
        {
            List<string> result = new List<string>();

            if (add_empty_item)
                result.Add(string.Empty);

            AllowedValuesCollection collection = GetProject(project_name).WorkItemTypes[item_type].FieldDefinitions[field].AllowedValues;

            foreach(var v in collection)
            {
                result.Add(v.ToString());
            }

            return result;
        }

        protected List<string> RecurseIterationNode(string node_name, NodeCollection nodes)
        {
            List<string> result = new List<string>();

            foreach (Node node in nodes)
            {
                if (node.IsIterationNode)
                {
                    result.Add(string.Format("{0}/{1}", node_name, node.Name));
                }

                result.AddRange(RecurseIterationNode(string.Format("{0}/{1}", node_name, node.Name), node.ChildNodes));
            }

            return result;
        }

        public List<QueryDefinition> GetQueries()
        {
            return GetQueries(Settings.Project);
        }

        public List<QueryDefinition> GetQueries(string project_name)
        {
            return RecurseQueryFolder(GetProject(project_name).QueryHierarchy);
        }

        protected List<QueryDefinition> RecurseQueryFolder(QueryFolder folder)
        {
            List<QueryDefinition> result = new List<QueryDefinition>();

            foreach (QueryItem item in folder)
            {
                if (item is QueryDefinition)
                {
                    if (QueryType.List == (item as QueryDefinition).QueryType)
                    {
                        result.Add(item as QueryDefinition);
                    }
                }

                if (item is QueryFolder)
                {
                    result.AddRange(RecurseQueryFolder(item as QueryFolder));
                }
            }

            return result;
        }

        public WorkItemCollection GetWorkItems(QueryDefinition query)
        {
            return GetWorkItems(Settings.Project, query);
        }

        public WorkItemCollection GetWorkItems(string project_name, QueryDefinition query)
        {
            var parameters = new Dictionary<string, string> { { "project", project_name } };

            return GetWorkItems(new Query(GetWorkItemStore(), query.QueryText, parameters));
        }

        public WorkItemCollection GetWorkItems(Query query)
        {
            return query.RunQuery();
        }

        public bool AddCommit(int[] workitem_ids, string commit_hash, string note, string description)
        {
            WorkItemType wit = GetProject().WorkItemTypes["GitCommit"];

            if (wit != null)
            {
                WorkItem wi = wit.NewWorkItem();
                wi.Fields[CoreField.Title].Value = note;
                wi.Fields[CoreField.Description].Value = description;
                wi.Fields["SourceControl.Git.Commit.Hash"].Value = commit_hash;
                wi.Save();

                foreach (int id in workitem_ids)
                {
                    WorkItem tmp_wi = GetWorkItemStore().GetWorkItem(id);
                    tmp_wi.Links.Add(new RelatedLink(wi.Id));
                    tmp_wi.Save();
                }
            }

            return true;
        }
    }
}
